#include <array>
#include <iostream>
#include <typeinfo>
#include <cassert>



class Any
{
    private:
        //父类只制定几个虚函数
        class holder {
            public:
                virtual ~holder() {}
                //纯虚函数:获取数据类型
                virtual const std::type_info& type() = 0;
                //通过一个 any对象构造一个any对象
                virtual holder* clone() = 0;
        };
        template<class T>
        class placeholder : public holder
        {
            public:
                placeholder(const T &val):_val(val){}//调用拷贝构造
                //纯虚函数:获取数据类型,获取子类对象保存的数据类型
                virtual const std::type_info& type() { return typeid(T); }
                //通过一个 any对象构造一个any对象,针对当前的对象自身,克隆出一个新的子类对象
                virtual holder* clone() { return new placeholder(_val); }
            public:
                T _val;//保存任意类型数据
        };
        holder* _content;
    public:
        Any() : _content(nullptr) {}
        template<class T>
        Any(const T& val) : _content(new placeholder<T>(val)) {}
        Any(const Any& other) : _content(other._content ? other._content->clone() : nullptr) {}
        ~Any(){ if(_content) delete _content;}

        Any& swap(Any &other){
            std::swap(_content,other._content);
            return *this;
        }

        template<class T>
        T *get(){
            //外界使用函数时,想要获取的数据类型必须和保存的数据类型一致
            assert(typeid(T) == _content->type());
            return &((placeholder<T>*)_content)->_val;
        }//返回子类对象保存数据的指针
        //赋值运算符的重载函数
        template<class T>
        Any& operator=(const T &val){
            //A = B 那就先用B中的值构造一个和B一样的临时对象C,然后让C与A交换,最后A中数据与C一致也就变相等于B赋值给A
            //并且我们也不用怕A中原本有数据会造成内存泄漏,因为临时对象C中带着原本A的指针,出了作用域C销毁进而调用析构就会清理掉
            //为val构造一个临时的通用容器,然后与当前容器自身进行指针交换,临时对象释放的时候,原本保存数据也就释放了
            Any(val).swap(*this);
            return *this;
        }
        Any& operator=(const Any &other){
            Any(other).swap(*this);
            return *this;
        }
};


//测试内存是否泄漏
class Test
{
    public:
        Test(){std::cout << "构造" << std::endl;}
        Test(const Test &t){std::cout << "拷贝构造" << std::endl;} 
        ~Test(){std::cout << "析构" << std::endl;} 
};

int main ()
{

    //练习C++17中的 any 类

    // Any a;
    // {
    //     Test t;
    //     a = t;
    // }
    // a = 666;
    // int *pa = a.get<int>();
    // std::cout << *pa << std::endl;

    // a = std::string("你好");
    // std::string *pstr = a.get<std::string>();
    // std::cout << *pstr << std::endl;

    return 0;
}